<!DOCTYPE html>
<html lang="zh-cn">

<head>
    <meta charset="UTF-8">
    <title class="title">[文件管理器]</title>
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
    <style type="text/css">
        .content {
            background: transparent;
        }

        .btn {
            position: relative;
            top: 0;
            left: 0;
            bottom: 0;
            right: 0;
        }

        .btn .file {
            position: fixed;
            z-index: 93;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
            width: 100%;
            opacity: 0;
        }
    </style>
</head>

<body>

   <div id="content" class="content">
        <div class="btn">
            <input @change="onChange" :accept="accept" ref="file" class="file" type="file" />
        </div>
    </div>

    <script type="text/javascript" src="js/vue.min.js"></script>
    <script type="text/javascript">
        let _this
        var vm = new Vue({
            el: '#content',
            data: {
                accept: ''
            },
            mounted() {
                console.log('加载webview')
                _this = this
                this.files = new Map()
                document.addEventListener('plusready', (e) => {
                    let {
                        debug,
                        instantly,
                        prohibited
                    } = plus.webview.currentWebview()
                    this.debug = debug
                    this.instantly = instantly
                    this.prohibited = prohibited
                    this.accept = prohibited.accept
                }, false)
            },
            methods: {
                toast(msg) {
                    plus.nativeUI.toast(msg)
                },
                clear(name) {
                    if (!name) {
                        this.files.clear()
                        return
                    }
                    this.files.delete(name)
                },
                setData(option = '{}') {
                    this.debug && console.log('更新参数：' + option)
                    try {
                        _this.option = JSON.parse(option)
                    } catch (e) {
                        console.error('参数设置错误')
                    }
                },
                async upload(name = '') {
                    if (name && this.files.has(name)) {
                        await this.createUpload(this.files.get(name))
                    } else {
                        for (let item of this.files.values()) {
                            if (item.type === 'waiting' || item.type === 'fail') {
                                await this.createUpload(item)
                            }
                        }
                    }
                },
                onChange(e) {
                    let fileDom = this.$refs.file
                    let file = fileDom.files[0]
                    let name = file.name
                    fileDom.value = ''
                    this.debug && console.log('文件名称', name, '大小', file.size)

                    if (file) {
                        // 限制文件格式
                        let suffix = name.substring(name.lastIndexOf('.') + 1).toLowerCase()
                        let formats = this.prohibited.formats.toLowerCase()
                        if (formats.includes(suffix)) {
                            this.toast(`不支持上传${suffix.toUpperCase()}格式文件`)
                            return
                        }
                        // 限制文件大小
                        if (file.size > 1024 * 1024 * Math.abs(this.prohibited.size)) {
                            this.toast(`附件大小请勿超过${this.prohibited.size}M`)
                            return
                        }
                        this.files.set(file.name, {
                            file,
                            name: file.name,
                            size: file.size,
                            progress: 0,
                            type: 'waiting'
                        })
                        this.callChange()
                        this.instantly && this.upload()
                    }
                },
                /**
                 * @returns {Map} 已选择的文件Map集
                 */
                callChange() {
                    location.href = 'callback?retype=change&files=' + escape(JSON.stringify([...this.files]))
                },
                /**
                 * @returns {object} 正在处理的当前对象
                 */
                changeFilesItem(item) {
                    this.files.set(item.name, item)
                    location.href = 'callback?retype=progress&item=' + escape(JSON.stringify(item))
                },
                createUpload(item) {
                    console.log('准备上传')
                    
                    item.type = 'loading'
                    delete item.responseText
                    return new Promise((resolve, reject) => {
                        console.log('loading', typeof this.option)
                        let {
                            url,
                            name,
                            method = 'POST',
                            header = {},
                            formData = {}
                        } = this.option
                        
                        let form = new FormData()
                        for (let keys in formData) {
                            form.append(keys, formData[keys])
                        }
                        form.append(name, item.file)
                        let xmlRequest = new XMLHttpRequest()
                        // let xmlRequest = new plus.net.XMLHttpRequest()
                        console.log('xmlRequest', xmlRequest)
                        for (let keys in header) {
                            xmlRequest.setRequestHeader(keys, header[keys])
                        }
                        xmlRequest.upload.addEventListener(
                            'progress',
                            event => {
                                if (event.lengthComputable) {
                                    let progress = Math.ceil((event.loaded * 100) / event.total)
                                    if (progress <= 100) {
                                        item.progress = progress
                                        this.changeFilesItem(item)
                                    }
                                }
                            },
                            false
                        )

                        xmlRequest.ontimeout = () => {
                            console.error('请求超时')
                            item.type = 'fail'
                            this.changeFilesItem(item)
                            return resolve(false)
                        }
                        xmlRequest.onreadystatechange = ev => {
                            console.log('onreadystatechange', xmlRequest.status)
                            if (xmlRequest.readyState == 4) {
                                if (xmlRequest.status == 200) {
                                    this.debug && console.log('上传完成：' + xmlRequest.responseText)
                                    item['responseText'] = xmlRequest.responseText
                                    item.type = 'success'
                                    this.changeFilesItem(item)
                                    return resolve(true)
                                } else if (xmlRequest.status == 0) {
                                    console.error('status = 0 :请检查请求头Content-Type与服务端是否匹配，服务端已正确开启跨域，并且nginx未拦截阻止请求')
                                }
                                console.error('--ERROR--：status = ' + xmlRequest.status)
                                item.type = 'fail'
                                this.changeFilesItem(item)
                                return resolve(false)
                            }
                        }
                        xmlRequest.open(method, url, true)
                        xmlRequest.send(form)
                    })
                }
            }
        })
    </script>
</body>

</html>
